// This File is part of the "nyaqt" Project
// 
// Copyright  2009 sometmes@gmail.com
// All rights reserved
// 
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.



using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Data.Common;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using nyaqt.Plugins;
using System.Data;
using System.ComponentModel;

namespace nyaqt
{
    public class EmptyConnectionInfo : ConnectionInfo
    {
    }

    [XmlType]
    public class ConnectionInfo : nyaqt.Plugins.IConnectionInfo, INotifyPropertyChanged
    {
        [XmlElement(Order = 5)]
        public DateTime Created { get { return _created; } set { _created = value; } }
        private DateTime _created;

        [XmlElement(Order = 6)]
        public DateTime LastUsed { get { return _lastUsed; } set { _lastUsed = value; } }
        private DateTime _lastUsed;

        IConnectionProperties connectionProperties = null;

        IDbConnection openConnection = null;

        string _providerInvariantName;
        [XmlElement(Order = 0)]
        public string ProviderInvariantName
        {
            get { return _providerInvariantName; }
            set
            {
                if (value != _providerInvariantName)
                {
                    _providerInvariantName = value;
                    _cnBuilder = null;
                    //CheckPasswordKey();
                    NotifyPropertyChanged("ProviderInvariantName");
                }
            }
        }

        int _version;
        [XmlElement(Order = 1)]
        public int Version
        {
            get { return _version; }
            set { _version = value; }
        }

        [XmlIgnore]
        public IConnectionProperties ConnectionProperties
        {
            get
            {
                if (this.connectionProperties == null)
                {
                    this.connectionProperties = ConnectionPropertiesPlugin.CreateInstance(this._providerInvariantName, this.Version);
                    this.connectionProperties.ConnectionInfo = this;
                    this.connectionProperties.Connection = this.openConnection;
                }
                return this.connectionProperties;
            }
        }

        internal NyaqtConnectionStringBuilder CreateNyaqtConnectionStringBuilder()
        {
            Dictionary<KnownNyaqtConnectionKeys, string> knownKeywords = new Dictionary<KnownNyaqtConnectionKeys, string>();
            Dictionary<string, string> keywordMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            ConnectionProperties.GetConnectionStringKeywordMap(knownKeywords, keywordMap);
            return new NyaqtConnectionStringBuilder(knownKeywords, keywordMap);
        }

        [XmlIgnore]
        public nyaqt.Plugins.NyaqtConnectionStringBuilder ConnectionStringBuilder
        {
            get
            {
                if (_cnBuilder == null)
                    _cnBuilder = CreateNyaqtConnectionStringBuilder();

                return _cnBuilder;
            }
        }

        [XmlIgnore]
        public IDbConnection Current
        {
            get
            {
                return this.openConnection;
            }

            set
            {
                if (value == null)
                {
                    this.connectionProperties = null;
                    this.openConnection = null;
                }
                else
                {
                    this.openConnection = value;
                    if (this.connectionProperties != null)
                        this.connectionProperties.Connection = value;
                }
            }
        }

        nyaqt.Plugins.NyaqtConnectionStringBuilder _cnBuilder = null;

        [XmlElement(Order = 3)]
        public string ConnectionString
        {
            get { return _connectionString; }
            set
            {
                ConnectionStringBuilder.ConnectionString = value;
                if (_cnBuilder.Password == null
                    && !string.IsNullOrEmpty(_password))
                {
                    _cnBuilder.Password = _password;
                }
                UpdateConnectionString(_cnBuilder);
            }
        }
        private string _connectionString = "";

        [XmlIgnore]
        public string ConnectionStringWithPwd
        {
            get
            {
                return _connectionStringWithPwd;
            }
        }
        private string _connectionStringWithPwd = "";

        [XmlIgnore]
        public string Password
        {
            get { return _password; }
            set
            {
                _cnBuilder.Password = value;
                UpdateConnectionString(_cnBuilder);
            }
        }

        [XmlElement(Order = 4)]
        public string PasswordEncrypted
        {
            get
            {
                return Lib.DPAPI.Encrypt(_password);
            }
            set
            {
                this.Password = Lib.DPAPI.Decrypt(value);
            }
        }
        private string _password = "";

        /// <summary>
        /// Updates this with Connection String changes in csb.
        /// csb gets password property stripped.
        /// </summary>
        /// <param name="csb"></param>
        public void UpdateConnectionString(nyaqt.Plugins.NyaqtConnectionStringBuilder csb)
        {
            bool changed = false;
            _connectionStringWithPwd = csb.ConnectionString;
            if (csb.Password != null)
            {
                string pwd = csb.Password;
                if (string.IsNullOrEmpty(pwd) || pwd == "****")
                    pwd = "";
                if (pwd != _password)
                {
                    _password = pwd;
                    changed = true;
                }
                csb.Password = null;
            }
            string cs = csb.ConnectionString;
            if (cs != _connectionString)
            {
                _connectionString = cs;
                changed = true;
            }
            if (changed)
            {
                _cnBuilder.ConnectionString = csb.ConnectionString;
                NotifyPropertyChanged("ConnectionString");
            }
        }

        [XmlElement(Order = 2)]
        public string ProviderName { get { return _providerName; } set { _providerName = value; } }
        private string _providerName;

        public ConnectionInfo()
        {
            _created = DateTime.Now;
        }

        public ConnectionInfo Copy()
        {
            ConnectionInfo newcon = new ConnectionInfo();
            newcon.ProviderInvariantName = this.ProviderInvariantName;
            newcon.ProviderName = this.ProviderName;
            newcon.Version = this.Version;
            newcon.ConnectionString = this.ConnectionString;
            newcon.Password = this.Password;

            return newcon;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        NyaqtProviderFactory _factory;
        [XmlIgnore]
        public NyaqtProviderFactory Factory
        {
            get
            {
                return _factory;
            }

            set
            {
                _factory = value;
            }
        }

        public IDbConnection CreateConnection()
        {
            IDbConnection cn = _factory.CreateConnection();
            cn.ConnectionString = this.ConnectionStringWithPwd;
            return cn;
        }

        public ConnectionInfo ChangeDatabase(string db)
        {
            nyaqt.Plugins.NyaqtConnectionStringBuilder builder = this.ConnectionStringBuilder.Copy();
            builder.Database = db;

            IConnectionInfo ci = connectionProperties.ConnectionInfo;
            ConnectionInfo newci = new ConnectionInfo();
            newci.ProviderInvariantName = ci.ProviderInvariantName;
            newci.ProviderName = ci.ProviderName;
            newci.Version = ci.Version;
            newci.ConnectionString = builder.ConnectionString;
            newci.Password = ci.Password;
            return newci;
        }
    }

    [XmlType]
    public class ConnectionInfoList
    {
        public ConnectionInfoList()
        {
        }

        public ConnectionInfoList(string providerInvariantName, int version)
        {
            _providerInvariantName = providerInvariantName;
        }

        public string ProviderInvariantName
        {
            get { return _providerInvariantName; }
            set { _providerInvariantName = value; }
        }

        private string _providerInvariantName;

        int _version;

        public int Version
        {
            get { return _version; }
            set { _version = value; }
        }

        private List<ConnectionInfo> _connections = new List<ConnectionInfo>();

        public List<ConnectionInfo> Connections
        {
            get { return _connections; }
            set { _connections = value; }
        }
    }

    [XmlType]
    public class ConnectionInfoMap 
        : System.Collections.ObjectModel.KeyedCollection<string, ConnectionInfoList>
    {
        protected override string GetKeyForItem(ConnectionInfoList item)
        {
            return item.ProviderInvariantName + ";" + item.Version;
        }

        public void RegisterConnection(ConnectionInfo ci)
        {
            ConnectionInfoList cl;
            if (this.Contains(ci.ProviderInvariantName + ";" + ci.Version))
                cl = this[ci.ProviderInvariantName + ";" + ci.Version];
            else
            {
                cl = new ConnectionInfoList();
                cl.ProviderInvariantName = ci.ProviderInvariantName;
                cl.Version = ci.Version;
                this.Add(cl);
            }

            foreach (ConnectionInfo ci2 in cl.Connections)
            {
                if (ci2.ConnectionString == ci.ConnectionString)
                {
                    cl.Connections.Remove(ci2);
                    break;
                }
            }
            cl.Connections.Insert(0, ci);
        }
    }
}
































